package com.wangjie.exception;

import com.google.common.collect.ImmutableBiMap;
import com.wangjie.response.CommonCode;
import com.wangjie.response.ResponseResult;
import com.wangjie.response.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.nio.file.AccessDeniedException;

/**
 * @author jieshao
 * @date 2021/10/15 11:39
 */
@ControllerAdvice
public class ExceptionCatch {
    private static final Logger logger = LoggerFactory.getLogger(ExceptionCatch.class);

    // 设置一个 Map, 存放异常类型和错误代码的映射, ImmutableBiMap 的特点是一旦创建不可改变, 并且线程安全
    private static ImmutableBiMap<Class<? extends Throwable>, ResultCode> EXCEPTIONS;
    // 使用 builder 来构建一个异常类型和错误代码的 Map 集合
    protected static ImmutableBiMap.Builder<Class<? extends Throwable>, ResultCode> builder = ImmutableBiMap.builder();

    // 捕获指定类型的异常, 该方法能捕获到所有的 CustomException 异常
    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseResult customException(CustomException e) {
        logger.error("catch exception: {}", e.getMessage());
        ResultCode resultCode = e.getResultCode();
        // 将异常信息转换为 json 数据返回页面展示
        return new ResponseResult(resultCode);
    }

    // 捕获系统异常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult exception(Exception e) {
        logger.error("catch exception: {}", e.getMessage());
        if (EXCEPTIONS == null) {
            // 如果 ImmutableBiMap 为空, 将 build 存放的 Map 数据加入到 ImmutableBiMap 中, 并且不可修改
            EXCEPTIONS = builder.build();
        }
        // 从 ImmutableBiMap 中获取异常类, 如果有指定异常类, 返回指定异常信息, 如果没有, 返回 99999 异常信息
        ResultCode resultCode = EXCEPTIONS.get(e.getClass());
        if (resultCode != null) {
            return new ResponseResult(resultCode);
        } else {
            return new ResponseResult(CommonCode.SERVER_ERROR);
        }
    }

    static {
        // 设置参数异常的提示
        builder.put(HttpMessageNotReadableException.class, CommonCode.INVALID_PARAM);
        // 设置权限不足的提示
        builder.put(AccessDeniedException.class, CommonCode.UNAUTHORISE);
    }
}